/**
 * Analisis y diseño de Algoritmos I
 * Bitmap.cpp
 */

// sacar comentario para usar en MVC++
//#if (defined(_MSC_VER) && defined(_MSC_VER))
//#include "stdafx.h"
//#endif

#include "Bitmap.h"
#include <stdlib.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Bitmap::Bitmap(FILE *fp) {
	read_header_bmp_image(fp,npx,npy);
	width=npx;
	heigth=npy;

	createImage(width,heigth);

    read_bmp_image(fp,npx,npy,imr,img,imb);
}


Bitmap::Bitmap(long width, long height) {
	this->width=npx=width;
	this->heigth=npy=height;
	createImage(width,height);
}

Bitmap::~Bitmap() {
	delete imr;
	delete img;
	delete imb;
}



void Bitmap::save(FILE *fp) {
	write_bmp_image(fp,width,heigth,0,imr,img,imb);
	fflush(fp);
}


unsigned long Bitmap::getColor(long x, long y) {
	return colorOf(x,y);
}


void Bitmap::setColor(long x, long y, unsigned long color) {
	char r,g,b;

	r = R(color);//(color && 0xff);
	g = G(color);//(color && 0xff00)>>8;
	b = B(color);//(color && 0xff0000)>>16;

	unsigned long pos = positionOf(x,y);

	imr[pos]=r;
	img[pos]=g;
	imb[pos]=b;
}

long Bitmap::getWidth() {
	return npx;
}

long Bitmap::getHeight() {
	return npy;
}


void Bitmap::createImage(long width, long height) {
    imr=(unsigned char*)malloc(sizeof(char)*width*heigth);
    img=(unsigned char*)malloc(sizeof(char)*width*heigth);
    imb=(unsigned char*)malloc(sizeof(char)*width*heigth);
}


int Bitmap::read_header_bmp_image(FILE *fp,long &npx, long &npy) {
	char BM[2];
	// read "BM" initial magic word
    fread(BM,sizeof(char),2,fp);
	// check if this two initial bytes begin with "BM"
    //if(!(BM[0]==66 && BM[1]==77)) {
    //    printf("\nERROR: Data in file not in bmp format\n");
    //    return(0);
    //}
	bmfh.bfType = (UINT) BM;

	// read next 16 dummy bytes
    //char dummy[24];
    //char dummy[835254];
    //fread(dummy,sizeof(char),835254,fp);
    //fread(dummy,sizeof(char),16,fp);


	fread(&bmfh.bfSize,sizeof(char),4,fp);
	fread(&bmfh.bfReserved1,sizeof(char),2,fp);
	fread(&bmfh.bfReserved2,sizeof(char),2,fp);
	fread(&bmfh.bfOffBits,sizeof(char),4,fp);

	fread(&bmih.biSize,sizeof(char),4,fp);


	// read number of columns
    //fread(&npx,sizeof(long),1,fp);
    fread(&bmih.biWidth,sizeof(char),4,fp);
	npx = bmih.biWidth;
	// read number of rows
    //fread(&npy,sizeof(long),1,fp);
    fread(&bmih.biHeight,sizeof(char),4,fp);
	npy = bmih.biHeight;
	// read next 4 dummy bytes

    char dummy[4],c;
    fread(dummy,sizeof(char),4,fp);

	//fread(&bmih.biPlanes,sizeof(char),2,fp);
	c = dummy[0];
	bmih.biPlanes = c;
	//fread(&bmih.biBitCount,sizeof(char),2,fp);
	c = dummy[2];
	bmih.biBitCount = c;

	// check if this bitmap have 24 bits depth color
    if (bmih.biBitCount/*dummy[2]*/ != 24)
        {
        printf("\nERROR: This program can only handle 24 bits depth color image");
        return(0);
        }
	// read next 24 dummy bytes
    //fread(dummy,sizeof(char),24,fp);
	fread(&bmih.biCompression,sizeof(char),4,fp);
	fread(&bmih.biSizeImage,sizeof(char),4,fp);
	fread(&bmih.biXPelsPerMeter,sizeof(char),4,fp);
	fread(&bmih.biYPelsPerMeter,sizeof(char),4,fp);
	fread(&bmih.biClrUsed,sizeof(char),4,fp);
	fread(&bmih.biClrImportant,sizeof(char),4,fp);

    return 1;
}

int Bitmap::read_bmp_image(FILE *fp,long npx, long npy, unsigned char *imr,unsigned char *img, unsigned char *imb) {
    long tamx = (npx*3/4)*4;
    if (tamx != 3*npx) tamx+=4;
    char *buf = (char *)malloc(sizeof(char)*tamx);

    unsigned char r,g,b;
    long ip=0;

    for (long iv=0; iv<npy; iv++) {
        for (long ih=0; ih<npx; ih++, ip++) {
            fread(&b,sizeof(char),1,fp);
            fread(&g,sizeof(char),1,fp);
            fread(&r,sizeof(char),1,fp);
            imr[ip]=r;
            img[ip]=g;
            imb[ip]=b;
        }
        long resto = tamx-3*npx;
        if (resto) fread(buf,sizeof(char),resto,fp);
    }
    return(1);
}


int Bitmap::write_bmp_image(FILE *fp,long npx, long npy, long numcan,
                   unsigned char *imr,unsigned char *img, unsigned char *imb) {
    unsigned char rgb[3];
    long tamx = (npx*3/4)*4;
    unsigned long aux;
    if (tamx != 3*npx) tamx+=4;

//  Escribe el header (54 bytes)
    fwrite("BM",sizeof(char),2,fp);
    aux = tamx*npy+54;
    fwrite(&aux,sizeof(long),1,fp); // tamanio del archivo
    aux = 0;  fwrite(&aux,sizeof(long),1,fp);
    aux = 54; fwrite(&aux,sizeof(long),1,fp);
    aux = 40; fwrite(&aux,sizeof(long),1,fp);
    fwrite(&npx,sizeof(long),1,fp);   // Numero de pixels en X
    fwrite(&npy,sizeof(long),1,fp);   // Numero de pixels en Y
    rgb[0]=1;rgb[1]=0;rgb[2]=24;
    fwrite(rgb,sizeof(char),3,fp);    //Numero de bits por color
    fwrite(rgb+1,sizeof(char),1,fp);
    aux = 0;  fwrite(&aux,sizeof(long),1,fp);
    aux = tamx*npy;
    fwrite(&aux,sizeof(long),1,fp); // tamanio de los datos
    aux = 0;  fwrite(&aux,sizeof(long),1,fp);
    aux = 0;  fwrite(&aux,sizeof(long),1,fp);
    aux = 0;  fwrite(&aux,sizeof(long),1,fp);
    aux = 0;  fwrite(&aux,sizeof(long),1,fp);

    unsigned char *buf = (unsigned char *)malloc(tamx*sizeof(char));
    buf[tamx-4]=buf[tamx-3]=buf[tamx-2]=buf[tamx-1]=0;
    long ip=0;
    for (long iv=0; iv<npy; iv++) {
        for (long ih=0; ih<npx; ih++, ip++) {
            if (numcan ==1) {
                buf[3*ih]=buf[3*ih+1]=buf[3*ih+2]=imr[ip];
            }
            else if (numcan == 2) {			//Asumimos que son 12 bits de informacion
                int col=imr[ip]*256+img[ip];
                buf[3*ih]  =(col)/16;
                buf[3*ih+1]=(col+8)/16;
                buf[3*ih+2]=0;
            }
            else {
                buf[3*ih]=imb[ip];
                buf[3*ih+1]=img[ip];
                buf[3*ih+2]=imr[ip];
            }
        }
        fwrite(buf,sizeof(char),tamx,fp);
    }
    return 1;
}


inline unsigned long Bitmap::colorOf(long x, long y) {
	unsigned long pos = positionOf(x,y);
	return rgb(imr[pos],img[pos],imb[pos]);
}

inline unsigned long Bitmap::indexColorOf(long x, long y) {
	unsigned long pos = positionOf(x,y);
	return rgb(imr[pos],img[pos],imb[pos]);
}

inline unsigned long Bitmap::positionOf(long col, long row) {
	return (heigth-row-1)*npx + col;
}

inline unsigned long Bitmap::rgb(unsigned char r, unsigned char g, unsigned char b) {
	return RGB(r,g,b);
}

